/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGEKNIFEC_IMAGEKNIFE_H
#define IMAGEKNIFEC_IMAGEKNIFE_H

#include "file_type_parser.h"
#include "imageknife_request.h"
#include "cache_key_generator.h"
#include <future>
#include "imageknife_node.h"
#include "transformation/transformation_constructor.h"

namespace ImageKnifePro {
/**
 * @brief ImageKnife 全局单例类，提供ImageKnife全局接口
 */
class ImageKnife {
public:
    virtual ~ImageKnife() = default;
    /**
     * @brief 获取ImageKnife 单例类对象
     * @return 返回ImageKnife对象引用
     */
    static ImageKnife &GetInstance();
    /**
     * @brief 初始化ImageKnife
     * 需要在主线程调用
     * 默认自动调用，但如果没有使用ImageKnife Napi层并且module的napi_init没有调起，则需要手动调用该函数进行初始化
     */
    virtual void Init() = 0;
    /**
     * @brief 初始化ImageKnife ArkTs接口，使用ArkTs接口需要调用该函数一次
     * @param env 为napi_env环境上下文
     * @param exports 为导出接口value的引用，为追加导出
     */
    virtual void InitImageKnifeArkTs(napi_env env, napi_value &exports) = 0;
    /**
     * @brief 主动取消一个加载请求
     * @param request 为需要取消的加载请求
     */
    virtual void CancelRequest(std::shared_ptr<ImageKnifeRequest> request) = 0;
    /**
     * @brief 设置全局默认的图片loader，ImageKnifeOption.loader如果为空，就会使用该loader进行加载
     * @param imageLoader 图片loader，可以添加指定的拦截器
     */
    virtual void SetDefaultImageKnifeLoader(std::shared_ptr<ImageKnifeLoader> imageLoader) = 0;
    /**
     * @brief 设置ImageKnife最大并发的请求数量
     * @param concurrency 为并发数量
     */
    virtual void SetMaxRequests(int concurrency) = 0;
    /**
     * @brief 设置缓存key生成器来自定义生成策略，没有调用该接口则使用默认的生成key策略
     * 调用后覆盖之前的key生成器并进行析构
     * @param keyPtr 为CacheKeyGenerator对象指针
     */
    virtual void SetCacheKeyGenerator(CacheKeyGenerator *keyPtr) = 0;
    /**
     * @brief 图片预加载，将图片预先加载至内存，文件中
     * @param imageKnifeOption 图片加载的相关设置
     * @return 返回加载的请求，可以用来取消下载
     */
    virtual std::shared_ptr<ImageKnifeRequest> Preload(std::shared_ptr<ImageKnifeOption> imageKnifeOption) = 0;

    /**
     * @brief 将外部获取的图片pixelmap，加入ImageKnifePro缓存中
     * @param url 图片地址url
     * @param imageData 需要缓存的图片数据
     * @param cacheType 写入缓存的类型，DEFAULT为同时写入文件和内存缓存，MEMORY为写入内存缓存，FILE为写入文件缓存
     * @param signature 缓存key自定义签名信息
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     */
    virtual void PutCacheImage(std::string url, std::shared_ptr<ImageData> imageData,
                               CacheStrategy cacheType = CacheStrategy::DEFAULT, std::string signature = "",
                               std::string cacheName = "") = 0;
    /**
     * @brief 初始化文件缓存，异步进行
     * 该接口只对默认文件缓存生效
     * @param sandbox 设置文件缓存文件的沙箱目录
     * @param size 设置最大图片缓存数量
     * @param maxDiskUsage 设置最大硬盘使用量
     * @param path 设置文件缓存的子目录，传入空string表示使用默认子目录
     * @return 返回异步future对象
     */
    virtual std::shared_future<void> InitFileCacheAsync(std::string sandbox = "", size_t size = 256,
                                                        size_t maxDiskUsage = 256 * 1024 * 1024,
                                                        std::string path = "ImageKnife") = 0;
    /**
     * @brief 添加小端文件缓存
     * 添加一个小端文件缓存实例至默认的文件缓存拦截器中
     * @param cacheName 小端文件缓存名称，不能为空，不能与其他的小端文件缓存名称一样
     * @param sandbox 文件缓存的沙箱目录
     * @param path 设置小端文件缓存的子目录，最终的缓存目录不能与大端缓存目录或其他小端目录一样
     * @return 返回缓存错误码
     */
    virtual CacheErrorCode AddSmallEndFileCache(std::string cacheName, std::string sandbox, std::string path) = 0;

    /**
     * @brief 初始化小端文件缓存
     * 初始化过程异步进行
     * @param cacheName 需要初始化的小端文件缓存名称
     * @param size 设置最大图片缓存数量
     * @param maxDiskUsage 设置最大硬盘使用量
     * @return 返回异步future对象
     */
    virtual std::shared_future<void> InitSmallEndFileCache(std::string cacheName, size_t maxSize = 128,
                                                           size_t maxDiskUsage = 128 * 1024 * 1024) = 0;
    /**
     * @brief 文件缓存启用文件拓展名
     * 调用后，写文件缓存时会添加文件拓展名
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     */
    virtual void FileCacheEnableExtension(std::string cacheName = "") = 0;
    /**
     * @brief 判断文件缓存初始化是否完成
     * 该接口只判断默认文件缓存的初始化状态
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     * @return 返回true表示初始化完成，返回false表示初始化未完成
     */
    virtual bool IsFileCacheInit(std::string cacheName = "") = 0;

    /**
     * @brief 获取文件和内存缓存的图片数量上限
     * 该接口只获取默认内存缓存，文件缓存的上限
     * @param cacheStrategy : 指定需要查询类型。CacheStrategy::FILE为查询文件缓存，其余枚举为查询内存缓存
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     * @return 文件或者内存图片数量上限, 获取文缓存上限失败返回-1
     */
    virtual int64_t GetCacheLimitNum(CacheStrategy cacheStrategy, std::string cacheName = "") = 0;
    /**
     * @brief 获取文件或者内存缓存字节数上限
     * 该接口只获取默认内存缓存，文件缓存的上限
     * @param cacheStrategy : 指定需要查询类型。CacheStrategy::FILE为查询文件缓存，其余枚举为查询内存缓存
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     * @return 文件或者内存字节数上限, 获取文缓存上限失败返回-1
     */
    virtual int64_t GetCacheLimitSize(CacheStrategy cacheStrategy, std::string cacheName = "") = 0;

    /**
     * @brief 设置文件或者内存缓存的使用上限
     * 该接口只设置默认文件缓存，内存缓存上限
     * 内存缓存的最大上限为1024*1024*1024(字节)，4096(图片张数)，超过该范围应用最大上限值
     * 大端文件缓存的最大上限为512*1024*1024(字节)，4096(图片张数)，超过该范围应用最大上限值
     * 小端文件文件缓存的最大上限为256*1024*1024(字节), 2048(图片张数), 超过该范围应用最大上限值
     * @param cacheStrategy : 指定需要设置的类型。CacheStrategy::FILE为设置文件缓存，其余枚举为设置内存缓存
     * @param maxSize 缓存的最大图片张数
     * @param maxUsage 最大的缓存使用量（字节）
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     */
    virtual void SetCacheLimit(CacheStrategy cacheStrategy, size_t maxSize, size_t maxUsage,
                               std::string cacheName = "") = 0;

    /**
     * @brief 获取磁盘或者内存缓存已缓存的图片数量
     * 该接口只对默认文件缓存，内存缓存有效
     * @param cacheStrategy : 指定需要查询类型。CacheStrategy::FILE为查询文件缓存，其余枚举为查询内存缓存
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     * @return 磁盘或者内存缓存图片数量,获取磁盘缓存图片数量返回值为-1时,文件缓存初始化未完成获取不到结果
     */
    virtual int64_t GetCurrentCacheNum(CacheStrategy cacheStrategy, std::string cacheName = "") = 0;

    /**
     * @brief 获取磁盘或者内存已用空间大小
     * 该接口只对默认文件缓存，内存缓存有效
     * @param cacheStrategy : 指定需要查询类型。CacheStrategy::FILE为查询文件缓存，其余枚举为查询内存缓存
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     * @return 磁盘或者内存已用空间大小,获取磁盘缓存已用空间返回值为-1时,文件缓存初始化未完成获取不到结果
     */
    virtual int64_t GetCurrentCacheSize(CacheStrategy cacheStrategy, std::string cacheName = "") = 0;

    /**
     * @brief 通过url清除指定文件缓存
     * 该接口只清除默认文件缓存中的数据
     * @param url 图片文件对应的url
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     * @return 返回异步future对象
     */
    virtual std::shared_future<void> RemoveFileAsync(std::string url, std::string cacheName = "") = 0;

    /**
     * @brief 通过ImageKnifeOption清除指定文件缓存
     * 该接口只清除默认文件缓存中的数据
     * @param option 图片文件对应的ImageKnifeOption
     * 可选：在option->fileCacheName中指定要操作的小端文件缓存，默认为大端
     * @return 返回异步future对象
     */
    virtual std::shared_future<void> RemoveFileAsync(std::shared_ptr<ImageKnifeOption> option) = 0;

    /**
     * @brief 通过ImageKnifeOption清除指定文件缓存
     * 该接口只清除默认文件缓存中的数据
     * @param option 图片文件对应的ImageKnifeOption
     * 可选：在option->fileCacheName中指定要操作的小端文件缓存，默认为大端
     * @param onComplete 完成后的回调，该回调确保在主线程中触发
     */
    virtual void RemoveFileAsync(std::shared_ptr<ImageKnifeOption> option, std::function<void()> onComplete) = 0;

    /**
     * @brief 清除所有文件缓存
     * 该接口只清除默认文件缓存中的数据
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     * @return 返回异步future对象
     */
    virtual std::shared_future<void> RemoveAllFileAsync(std::string cacheName = "") = 0;

    /**
     * @brief 清除所有文件缓存
     * 该接口只清除默认文件缓存中的数据
     * @param onComplete 完成后的回调，该回调确保在主线程中触发
     * @param cacheName 需要操作的文件缓存名称，默认名称为空即操作大端文件缓存, 不为空则匹配小端文件缓存
     */
    virtual void RemoveAllFileAsync(std::function<void()> onComplete, std::string cacheName = "") = 0;

    /**
     * @brief 清除所有内存缓存
     * 该接口只清除默认内存缓存中的数据
     */
    virtual void RemoveAllMemoryCache() = 0;

    /**
     * @brief 通过url清除指定内存缓存
     * 该接口只清除默认内存缓存中的数据
     * @param url 图片缓存对应的url
     */
    virtual void RemoveMemoryCache(std::string url) = 0;

    /**
     * @brief 通过ImageKnifeOption清除指定内存缓存
     * 该接口只清除默认内存缓存中的数据
     * @param imageKnifeOption 图片缓存对应的ImageKnifeOption
     */
    virtual void RemoveMemoryCache(std::shared_ptr<ImageKnifeOption> imageKnifeOption) = 0;

    /**
     * @brief 为ArkTs接口注册非默认的ImageKnifeLoader，使得ArkTs层的ImageKnifeOption通过字符串选择对应的loader对象
     * 使用C API直接在C侧ImageKnifeOption对象上直接指定loader成员，无需调用该函数注册
     * @param name 注册的loader名称字符串
     * @param loader 注册的ImageKnifeLoader对象智能指针
     */
    virtual void RegisterLoader(std::string name, std::shared_ptr<ImageKnifeLoader> loader) = 0;

    /**
     * @brief 为ArkTs接口注册自定义的Transformation，使得ArkTs层的ImageKnifeOption通过字符串选择对应的Transformation对象
     * 使用C API直接在C侧ImageKnifeOption对象上直接指定Transformation成员，无需调用该函数注册
     * @param name 注册的Transformation名称字符串
     * @param transformation 注册的自定义Transformation对象智能指针
     */
    virtual void RegisterTransformation(std::string name, std::shared_ptr<Transformation> transformation) = 0;

    /**
     * @brief 为ArkTs接口注册自定义的图形变换构造者对象，ArkTs层的ImageKnifeOption通过字符串选择对应的TransformationConstructor对象
     * 通过图形变换构造者，可以接收ArkTs层的图形变换参数TransformationOption，进而创建具体Transformation对象
     * @param name 注册的TransformationConstructor名称字符串
     * @param constructor 注册的TransformationConstructor对象智能指针
     */
    virtual void RegisterTransformationConstructor(std::string name,
                                                   std::shared_ptr<TransformationConstructor> constructor) = 0;

    /**
     * @brief 重新加载请求，忽略已过期、已加载成功的请求。不能用于预加载请求的重试
     * Preload, PreloadCache, GetImageCache等接口发起的请求，需要重试请再调用一次对应接口
     * @param requestId 图片加载请求的ID信息，通过ImageInfo.requestId获取
     */
    virtual void Reload(std::string requestId) = 0;

    /**
     * @brief 全局添加单个请求头header
     * @param key 请求头属性
     * @param value 请求头值
     */
    virtual void AddHeader(std::string key, std::string value) = 0;

    /**
     * @brief 删除单个请求头header
     * @param key 请求头属性
     */
    virtual void DeleteHeader(std::string key) = 0;

    /**
     * @brief 预加载图片, 返回文件缓存的对应文件路径
     * @param option 加载图片对应的参数选项
     * @return 返回异步future对象，加载成功时future.get获取到正常文件路径，加载失败时获取的是空字符串
     */
    virtual std::shared_future<std::string> PreloadCache(std::shared_ptr<ImageKnifeOption> option) = 0;

    /**
     * @brief 预加载图片，获取文件缓存的对应文件路径
     * @param option 加载图片对应的参数选项
     * @param onComplete 加载完成后的回调，可取得文件路径，该回调确保在主线程中触发
     */
    virtual void PreloadCache(std::shared_ptr<ImageKnifeOption> option,
                              std::function<void(std::string)> onComplete) = 0;

    /**
     * @brief 从内存或文件缓存中获取图片数据，若没有对应缓存，则去加载图片
     * @param loadSrc 图片地址url
     * @param cacheType : 缓存策略
     * 值为CacheStrategy::DEFAULT时尝试从内存，文件缓存中获取数据
     * 值为CacheStrategy::MEMORY时仅从内存缓存中取数据
     * 值为CacheStrategy::FILE时仅从文件缓存中取数据
     * 值为CacheStrategy::NONE时不使用缓存，直接去加载图片
     * @param signature 缓存key自定义签名信息
     * @param animator 生成key是否以动图的方式处理，默认为false，动图的图片数据是多帧pixelmap的数组
     * @return 返回future对象可以获取图片数据ImageData对象的智能指针
     * 原始指针OH_PixelmapNative 可以通过ImageData->GetPixelmap获取，或者使用GetPixelmapList获取pixelmap数组
     * 原始指针OH_PixelmapNative 的析构由ImageData管理，不要对原始指针调用release接口
     */
    virtual std::shared_future<std::shared_ptr<ImageData>> GetCacheImage(std::string loadSrc,
        CacheStrategy cacheType = CacheStrategy::DEFAULT, std::string signature = "", bool animator = false) = 0;

    /**
     * @brief 从内存或文件缓存中获取图片数据，若没有对应缓存，则去加载图片
     * 无法获取逐帧解码模式下的动图图片数据，因为解码是实时的，没有以pixelmap数组的形式缓存
     * @param option 加载图片对应的参数选项
     * @param cacheType : 缓存策略
     * 值为CacheStrategy::DEFAULT时尝试从内存，文件缓存中获取数据
     * 值为CacheStrategy::MEMORY时仅从内存缓存中取数据
     * 值为CacheStrategy::FILE时仅从文件缓存中取数据
     * 值为CacheStrategy::NONE时不使用缓存，直接去加载图片
     * @param signature 缓存key自定义签名信息，覆盖option中的signature设置
     * @param animator 生成key是否以动图的方式处理，默认为false，动图的图片数据是多帧pixelmap的数组
     * 该参数已不需要，无论animator是否为ture，都可以获取多帧pixelmap，取决于图片实际帧数
     * @return 返回future对象可以获取图片数据ImageData对象的智能指针
     * 原始指针OH_PixelmapNative 可以通过ImageData->GetPixelmap获取，或者使用GetPixelmapList获取pixelmap数组
     * 原始指针OH_PixelmapNative 的析构由ImageData管理，不要对原始指针调用release接口
     */
    virtual std::shared_future<std::shared_ptr<ImageData>> GetCacheImage(std::shared_ptr<ImageKnifeOption> option,
        CacheStrategy cacheType = CacheStrategy::DEFAULT, std::string signature = "", bool animator = false) = 0;

    /**
     * @brief 从内存或文件缓存中获取图片数据，若没有对应缓存，则去加载图片
     * 无法获取逐帧解码模式下的动图图片数据，因为解码是实时的，没有以pixelmap数组的形式缓存
     * @param option 加载图片对应的参数选项
     * 如果匹配的缓存key需要添加signature签名信息，在option->signature中描述
     * @param onComplete 完成后的回调，可取得图片数据，该回调确保在主线程触发
     * @param cacheType 缓存策略
     * 值为CacheStrategy::DEFAULT时尝试从内存，文件缓存中获取数据
     * 值为CacheStrategy::MEMORY时仅从内存缓存中取数据
     * 值为CacheStrategy::FILE时仅从文件缓存中取数据
     * 值为CacheStrategy::NONE时不使用缓存，直接去加载图
     */
    virtual void GetCacheImage(std::shared_ptr<ImageKnifeOption> option,
        std::function<void(std::shared_ptr<ImageData>)> onComplete,
        CacheStrategy cacheType = CacheStrategy::DEFAULT) = 0;

    /**
     * @brief 设置自定义日志输出回调函数
     * 如果没有进行设置，则使用默认的日志输出函数
     * @param logPrinter 自定义日志输出函数
     */
    virtual void SetCustomLogPrinter(LogPrinter logPrinter) = 0;
    /**
     * @brief 设置自定义的文件类型解析对象
     * 如果没有进行设置，则使用默认的文件类型解析对象进行图片格式判断
     * @param fileTypeParser 文件类型解析对象
     */
    virtual void SetFileTypeParser(std::shared_ptr<FileTypeParser> fileTypeParser) = 0;

    /**
     * @brief 为默认的网络下载设置全局的自定义Dns规则
     * @param dnsOption 自定义Dns配置项
     */
    virtual void SetGlobalDnsOption(std::shared_ptr<DnsOption> dnsOption) = 0;
};
}

#endif // IMAGEKNIFEC_IMAGEKNIFE_H
